package com.szh.gulimall.product.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.szh.common.constant.ProductConstant;
import com.szh.gulimall.product.dao.AttrAttrgroupRelationDao;
import com.szh.gulimall.product.dao.AttrGroupDao;
import com.szh.gulimall.product.dao.CategoryDao;
import com.szh.gulimall.product.entity.AttrAttrgroupRelationEntity;
import com.szh.gulimall.product.entity.AttrGroupEntity;
import com.szh.gulimall.product.entity.CategoryEntity;
import com.szh.gulimall.product.service.CategoryService;
import com.szh.gulimall.product.vo.AttrGroupRelationVo;
import com.szh.gulimall.product.vo.AttrRespVo;
import com.szh.gulimall.product.vo.AttrVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.szh.common.utils.PageUtils;
import com.szh.common.utils.Query;

import com.szh.gulimall.product.dao.AttrDao;
import com.szh.gulimall.product.entity.AttrEntity;
import com.szh.gulimall.product.service.AttrService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

@Service("attrService")
public class AttrServiceImpl extends ServiceImpl<AttrDao, AttrEntity> implements AttrService {

    @Autowired
    private AttrAttrgroupRelationDao relationDao;

    @Autowired
    private AttrGroupDao attrGroupDao;

    @Autowired
    private CategoryDao categoryDao;

    @Autowired
    private CategoryService categoryService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<AttrEntity> page = this.page(
                new Query<AttrEntity>().getPage(params),
                new QueryWrapper<>()
        );
        return new PageUtils(page);
    }

    /**
     * 保存属性与属性分组的关联关系
     */
    @Override
    @Transactional
    public void saveAttr(AttrVo attr) {
        //保存基本数据
        AttrEntity attrEntity = new AttrEntity();
        BeanUtils.copyProperties(attr, attrEntity);
        this.save(attrEntity);
        if (attr.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()
            && Objects.nonNull(attr.getAttrGroupId())) {
            //保存关联关系
            AttrAttrgroupRelationEntity entity = new AttrAttrgroupRelationEntity();
            entity.setAttrGroupId(attr.getAttrGroupId());
            entity.setAttrId(attrEntity.getAttrId());
            relationDao.insert(entity);
        }
    }

    /**
     * 获取某个分类下的所有属性信息
     * attrType: 属性类型, 0-销售属性, 1-规格参数
     */
    @Override
    public PageUtils queryBaseAttrList(Map<String, Object> params, Long catelogId, String type) {
        QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<>();
        Integer attrType = "base".equalsIgnoreCase(type) ?
                ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode() : ProductConstant.AttrEnum.ATTR_TYPE_SALE.getCode();
        queryWrapper.eq("attr_type", attrType);
        if (catelogId != 0) {
            queryWrapper.eq("catelog_id", catelogId);
        }
        String key = (String) params.get("key");
        if (!StringUtils.isEmpty(key)) {
            queryWrapper.and(obj -> obj.eq("attr_id", key).or().like("attr_name", key));
        }
        IPage<AttrEntity> page = this.page(
                new Query<AttrEntity>().getPage(params),
                queryWrapper
        );
        PageUtils pageUtils = new PageUtils(page);
        List<AttrEntity> records = page.getRecords();

        Map<Long, Long> relationMap = new HashMap<>();
        Map<Long, String> attrGroupMap = new HashMap<>();
        if ("base".equalsIgnoreCase(type)) {
            //设置分组信息：批量查询，首先将所有属性id映射为List集合
            List<Long> attrIds = records.stream().map(AttrEntity::getAttrId).collect(Collectors.toList());
            //根据所有属性id一次性查询出 属性-分组表中的数据
            QueryWrapper<AttrAttrgroupRelationEntity> wrapper = new QueryWrapper<>();
            wrapper.in("attr_id", attrIds);
            List<AttrAttrgroupRelationEntity> attrgroupRelationEntities = relationDao.selectList(wrapper);
            //将 属性-分组表中的数据，以attr_id为key、attr_group_id为value，映射为Map
            relationMap = attrgroupRelationEntities.stream().collect(Collectors.toMap(AttrAttrgroupRelationEntity::getAttrId, AttrAttrgroupRelationEntity::getAttrGroupId));
            //将Map中的value取出，也即将所有属性分组id组装成Collection集合
            Collection<Long> attrGroupIds = relationMap.values();
            //根据所有属性分组id一次性查询出 分组表中的数据
            List<AttrGroupEntity> attrGroupEntities = attrGroupDao.selectBatchIds(attrGroupIds);
            //将 分组表中的数据，以attr_group_id为key、attr_group_name为value，映射为Map
            attrGroupMap = attrGroupEntities.stream().collect(Collectors.toMap(AttrGroupEntity::getAttrGroupId, AttrGroupEntity::getAttrGroupName));
        }
        //设置分类信息：批量查询，首先将所有分类id映射为List集合
        List<Long> categoryIds = records.stream().map(AttrEntity::getCatelogId).collect(Collectors.toList());
        //根据所有分类id一次性查询出 分类表中的数据
        List<CategoryEntity> categoryEntities = categoryDao.selectBatchIds(categoryIds);
        //将 分类表中的数据，以cat_id为key、cat_name为value，映射为Map
        Map<Long, String> categoryMap = categoryEntities.stream().collect(Collectors.toMap(CategoryEntity::getCatId, CategoryEntity::getName, (o1, o2) -> o1));

        List<AttrRespVo> attrRespVoList = new ArrayList<>();
        for (AttrEntity attrEntity : records) {
            AttrRespVo attrRespVo = new AttrRespVo();
            BeanUtils.copyProperties(attrEntity, attrRespVo);
            if ("base".equalsIgnoreCase(type)) {
                //设置分组的名称
                if (attrGroupMap.containsKey(relationMap.get(attrEntity.getAttrId()))) {
                    attrRespVo.setGroupName(attrGroupMap.get(relationMap.get(attrEntity.getAttrId())));
                }
            }
            //设置分类的名称
            if (categoryMap.containsKey(attrEntity.getCatelogId())) {
                attrRespVo.setCatelogName(categoryMap.get(attrEntity.getCatelogId()));
            }
            attrRespVoList.add(attrRespVo);
        }
        pageUtils.setList(attrRespVoList);
        return pageUtils;
    }

    /**
     * 根据属性id查询详细信息，同时设置分组信息、分类全路径
     * 为search检索服务提供的远程接口，考虑到远程调用可能会比较耗时，所以将返回结果放入Redis缓存中
     */
    @Cacheable(cacheNames = {"attr"}, key = "'attrInfo:' + #root.args[0]")
    @Override
    public AttrRespVo queryAttrInfo(Long attrId) {
        AttrEntity attrEntity = this.getById(attrId);
        AttrRespVo attrRespVo = new AttrRespVo();
        BeanUtils.copyProperties(attrEntity, attrRespVo);
        if (attrEntity.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()) {
            //设置分组信息
            QueryWrapper<AttrAttrgroupRelationEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("attr_id", attrId);
            AttrAttrgroupRelationEntity entity = relationDao.selectOne(queryWrapper);
            if (!Objects.isNull(entity)) {
                attrRespVo.setAttrGroupId(entity.getAttrGroupId());
                AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(entity.getAttrGroupId());
                if (!Objects.isNull(attrGroupEntity)) {
                    attrRespVo.setGroupName(attrGroupEntity.getAttrGroupName());
                }
            }
        }
        //设置分类信息
        Long catelogId = attrEntity.getCatelogId();
        Long[] catelogPath = categoryService.queryCatelogPath(catelogId);
        attrRespVo.setCatelogPath(catelogPath);
        CategoryEntity categoryEntity = categoryService.getById(catelogId);
        if (!Objects.isNull(categoryEntity)) {
            attrRespVo.setCatelogName(categoryEntity.getName());
        }
        return attrRespVo;
    }

    /**
     * 修改属性信息，同时修改属性分组的关联信息
     */
    @Override
    @Transactional
    public void updateAttr(AttrVo attr) {
        AttrEntity attrEntity = new AttrEntity();
        BeanUtils.copyProperties(attr, attrEntity);
        this.updateById(attrEntity);
        if (attrEntity.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()) {
            //修改分组关联数据
            AttrAttrgroupRelationEntity entity = new AttrAttrgroupRelationEntity();
            entity.setAttrId(attr.getAttrId());
            entity.setAttrGroupId(attr.getAttrGroupId());
            //根据attr_id查询属性分组关联表中的数据，如果有数据则是更新操作，没有则是新增操作
            Integer count = relationDao.selectCount(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attr.getAttrId()));
            if (count > 0) {
                relationDao.update(entity, new UpdateWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attr.getAttrId()));
            } else {
                relationDao.insert(entity);
            }
        }
    }

    /**
     * 根据属性分组id查询当前属性分组关联的所有属性信息（规格参数/基本属性）
     */
    @Override
    public List<AttrEntity> queryAttrRelation(Long attrGroupId) {
        QueryWrapper<AttrAttrgroupRelationEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("attr_group_id", attrGroupId);
        List<AttrAttrgroupRelationEntity> relationEntityList = relationDao.selectList(queryWrapper);
        List<Long> attrIds = relationEntityList.stream().map(AttrAttrgroupRelationEntity::getAttrId)
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(attrIds)) {
            return new ArrayList<>();
        }
        Collection<AttrEntity> attrEntities = this.listByIds(attrIds);
        return (List<AttrEntity>) attrEntities;
    }

    /**
     * 根据属性分组id查询当前属性分组没有被其他分组关联的所有属性信息（规格参数/基本属性）
     */
    @Override
    public PageUtils queryNoAttrRelation(Map<String, Object> params, Long attrGroupId) {
        //1.当前分组只能关联自己所属分类中的所有属性
        AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(attrGroupId);
        Long catelogId = attrGroupEntity.getCatelogId();
        //2.当前分组只能关联其他分组没有关联的那些属性
        //2.1 查询当前分类下的其他分组
        QueryWrapper<AttrGroupEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("catelog_id", catelogId);
        List<AttrGroupEntity> attrGroupEntityList = attrGroupDao.selectList(queryWrapper);
        //2.2 查出这些分组关联的所有属性
        List<Long> attrGroupIds = attrGroupEntityList.stream().map(AttrGroupEntity::getAttrGroupId)
                .collect(Collectors.toList());
        QueryWrapper<AttrAttrgroupRelationEntity> wrapper = new QueryWrapper<>();
        wrapper.in("attr_group_id", attrGroupIds);
        List<AttrAttrgroupRelationEntity> relationEntityList = relationDao.selectList(wrapper);
        //2.3 从当前分类的所有属性中剔除其他分组已经关联的那些属性
        List<Long> attrIds = relationEntityList.stream().map(AttrAttrgroupRelationEntity::getAttrId)
                .collect(Collectors.toList());
        QueryWrapper<AttrEntity> query = new QueryWrapper<>();
        query.eq("catelog_id", catelogId).eq("attr_type", ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode());
        if (!CollectionUtils.isEmpty(attrIds)) {
            query.notIn("attr_id", attrIds);
        }
        String key = (String) params.get("key");
        if (!StringUtils.isEmpty(key)) {
            query.and(obj -> obj.eq("attr_id", key).or().like("attr_name", key));
        }
        IPage<AttrEntity> page = this.page(
                new Query<AttrEntity>().getPage(params),
                query
        );
        return new PageUtils(page);
    }

    /**
     * 删除属性分组的关联关系，只删除关联关系，不删除属性
     */
    @Override
    public void deleteAttrRelationBatch(AttrGroupRelationVo[] vos) {
        List<AttrAttrgroupRelationEntity> relationEntityList = Arrays.stream(vos).map(item -> {
            AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
            BeanUtils.copyProperties(item, relationEntity);
            return relationEntity;
        }).collect(Collectors.toList());
        relationDao.deleteAttrRelationBatch(relationEntityList);
    }

    /**
     * 在指定的属性集合中查询出可以被检索的那些属性id
     */
    @Override
    public List<Long> selectSearchAttrIds(List<Long> attrIds) {
        return baseMapper.selectSearchAttrIds(attrIds);
    }

}